#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

#define SERVER_PORT 60000
#define SERVER_IP "192.168.2.146"

// 函数声明
void delete_temp_client(int socket);

// 定义发送信息的结构体(自定义)
struct msg
{
    char buf[1024];
    char name[20];
    char passward[20];
    struct sockaddr_in other_addr;
    int flag; // 用来区分注册 登录 还是发送信息
};

// 定义双向循环链表节点
struct client_node
{
    int socket;
    struct sockaddr_in other_addr;
    char name[20];
    struct client_node *prev;
    struct client_node *next;
};

// 定义好友关系
struct friend_relation
{
    char name1[20];
    char name2[20];
};

// 临时保存客户端连接信息的结构体
struct temp_client
{
    int socket;
    struct sockaddr_in other_addr;
};

struct client_node *client_list;
struct friend_relation friends[100];
int friend_count = 0;
struct temp_client temp_clients[100];
int temp_client_count = 0;
struct user
{
    char name[20];
    char passward[20];
};
struct user users[100];
int user_count = 0;

// 初始化双向循环链表
void init_client_list()
{
    client_list = (struct client_node *)malloc(sizeof(struct client_node));
    if (client_list == NULL)
    {
        perror("malloc fail");
        exit(EXIT_FAILURE);
    }
    client_list->socket = 0;
    client_list->prev = client_list;
    client_list->next = client_list;
}

// 绑定好友关系
void bind_friends(const char *name1, const char *name2)
{
    strcpy(friends[friend_count].name1, name1);
    strcpy(friends[friend_count].name2, name2);
    friend_count++;
}

// 查找好友节点
struct client_node *find_friend_node(const char *name)
{
    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (strcmp(current->name, name) == 0)
        {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 根据IP和端口查找客户端节点
struct client_node *find_client_by_ip_port(const char *ip_str, int port)
{
    struct in_addr target_ip;
    inet_pton(AF_INET, ip_str, &target_ip);

    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (current->other_addr.sin_addr.s_addr == target_ip.s_addr &&
            ntohs(current->other_addr.sin_port) == port)
        {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 根据用户名查找客户端节点
struct client_node *find_client_by_name(const char *name)
{
    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (strcmp(current->name, name) == 0)
        {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 根据套接字查找客户端节点
struct client_node *find_client_by_socket(int socket_client)
{
    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (current->socket == socket_client)
        {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 添加客户端到链表
void add_client_to_list(int socket_client, struct sockaddr_in client_addr, const char *name)
{
    struct client_node *new_node = (struct client_node *)malloc(sizeof(struct client_node));
    if (new_node == NULL)
    {
        perror("malloc fail");
        return;
    }
    new_node->socket = socket_client;
    new_node->other_addr = client_addr;
    strcpy(new_node->name, name);

    // 插入到链表尾部
    new_node->prev = client_list->prev;
    new_node->next = client_list;
    client_list->prev->next = new_node;
    client_list->prev = new_node;
}

// 删除客户端信息
void delete_client_from_list(int socket_client)
{
    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (current->socket == socket_client)
        {
            current->prev->next = current->next;
            current->next->prev = current->prev;
            free(current);
            printf("客户端从链表中删除，socket=%d\n", socket_client);
            delete_temp_client(socket_client); // 同时删除临时信息
            return;
        }
        current = current->next;
    }
    printf("警告: 未找到socket=%d的客户端信息\n", socket_client);
}

// 删除临时客户端信息
void delete_temp_client(int socket)
{
    for (int i = 0; i < temp_client_count; i++)
    {
        if (temp_clients[i].socket == socket)
        {
            // 将后面的元素前移
            for (int j = i; j < temp_client_count - 1; j++)
            {
                temp_clients[j] = temp_clients[j + 1];
            }
            temp_client_count--;
            break;
        }
    }
}

// 查找临时客户端信息
struct sockaddr_in *find_temp_client_addr(int socket)
{
    for (int i = 0; i < temp_client_count; i++)
    {
        if (temp_clients[i].socket == socket)
        {
            return &temp_clients[i].other_addr;
        }
    }
    return NULL;
}

// 添加临时客户端信息
void add_temp_client(int socket, struct sockaddr_in addr)
{
    temp_clients[temp_client_count].socket = socket;
    temp_clients[temp_client_count].other_addr = addr;
    temp_client_count++;
}

// 打印链表中的客户端信息
void print_client_list()
{
    printf("\n===== 当前在线客户端列表 =====\n");
    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        printf("socket_client:%d ip:%s port:%d name:%s\n",
               current->socket,
               inet_ntoa(current->other_addr.sin_addr),
               ntohs(current->other_addr.sin_port),
               current->name);
        current = current->next;
    }
    printf("==============================\n\n");
}


// 广播在线状态
void broadcast_online_status(const char *name, int status)
{
    for (int i = 0; i < friend_count; i++)
    {
        struct client_node *target = NULL;
        if (strcmp(friends[i].name1, name) == 0)
        {
            target = find_friend_node(friends[i].name2);
        }
        else if (strcmp(friends[i].name2, name) == 0)
        {
            target = find_friend_node(friends[i].name1);
        }

        if (target != NULL)
        {
            char status_msg[1024];
            if (status)
            {
                snprintf(status_msg, sizeof(status_msg), "%s 已上线", name);
            }
            else
            {
                snprintf(status_msg, sizeof(status_msg), "%s 已下线", name);
            }
            send(target->socket, status_msg, strlen(status_msg), 0);
        }
    }
}

// 获取好友在线列表
void get_friend_online_list(const char *name, char *list)
{
    list[0] = '\0';
    strcat(list, "===== 在线好友列表 =====\n");

    struct client_node *current = client_list->next;
    while (current != client_list)
    {
        if (strcmp(current->name, name) != 0)
        {
            char status_line[1024];
            snprintf(status_line, sizeof(status_line), "- %s (在线) ip:%s port:%d\n",
                     current->name, inet_ntoa(current->other_addr.sin_addr),
                     ntohs(current->other_addr.sin_port));
            strcat(list, status_line);
        }
        current = current->next;
    }

    strcat(list, "=======================");
    if (strlen(list) == 27)
    { // 只有标题和分隔线的长度
        strcat(list, "\n无在线好友");
    }
}

// 子线程中接收客户端数据
void *recv_buf(void *arg)
{
    pthread_detach(pthread_self());

    int ret;
    int socket_client = *(int *)arg;
    struct msg buffer;
    int bytes_received = 0;

    while (1)
    {
        // 清空缓冲区
        memset(&buffer, 0, sizeof(buffer));

        // 接收数据
        ret = recv(socket_client, &buffer, sizeof(buffer), 0);

        if (ret < 0)
        {
            printf("recv error, socket=%d\n", socket_client);
            struct client_node *node = find_client_by_socket(socket_client);
            if (node != NULL)
            {
                broadcast_online_status(node->name, 0);
            }
            delete_client_from_list(socket_client);
            close(socket_client);
            print_client_list();
            return NULL;
        }
        else if (ret == 0)
        {
            printf("client down, socket=%d\n", socket_client);
            struct client_node *node = find_client_by_socket(socket_client);
            if (node != NULL)
            {
                broadcast_online_status(node->name, 0);
            }
            delete_client_from_list(socket_client);
            close(socket_client);
            print_client_list();
            return NULL;
        }

        // 处理接收到的数据
        if (ret > 0)
        {
            if (buffer.flag == 1)
            { // 注册
                int found = 0;
                for (int i = 0; i < user_count; i++)
                {
                    if (strcmp(users[i].name, buffer.name) == 0)
                    {
                        found = 1;
                        break;
                    }
                }
                if (found)
                {
                    send(socket_client, "Register Fail", strlen("Register Fail"), 0);
                }
                else
                {
                    strcpy(users[user_count].name, buffer.name);
                    strcpy(users[user_count].passward, buffer.passward);
                    user_count++;
                    send(socket_client, "Register Success", strlen("Register Success"), 0);
                }
            }
            else if (buffer.flag == 2)
            { // 登录
                int found = 0;
                for (int i = 0; i < user_count; i++)
                {
                    if (strcmp(users[i].name, buffer.name) == 0 && strcmp(users[i].passward, buffer.passward) == 0)
                    {
                        found = 1;
                        break;
                    }
                }
                if (found)
                {
                    // 查找客户端地址信息
                    struct sockaddr_in *client_addr = find_temp_client_addr(socket_client);

                    if (client_addr != NULL)
                    {
                        // 使用临时保存的地址信息
                        add_client_to_list(socket_client, *client_addr, buffer.name);
                    }
                    else
                    {
                        printf("警告: 未找到socket=%d的临时地址信息\n", socket_client);
                        // 使用默认地址信息（这会导致IP和端口显示为0）
                        struct sockaddr_in default_addr = {0};
                        add_client_to_list(socket_client, default_addr, buffer.name);
                    }
                    broadcast_online_status(buffer.name, 1);
                    send(socket_client, "Login Success", strlen("Login Success"), 0);
                    send(socket_client, "Login Success", strlen("Login Success"), 0);
                    print_client_list(); // 登录成功后打印在线客户端列表
                }
                else
                {
                    send(socket_client, "Login Fail", strlen("Login Fail"), 0);
                    send(socket_client, "Login Fail", strlen("Login Fail"), 0);
                }
            }
            else if (buffer.flag == 3)
            { // 发消息
                // 查找发送者客户端
                struct client_node *sender_node = find_client_by_socket(socket_client);

                if (sender_node != NULL)
                {
                    printf("接收到的信息[ip:%s port:%d]buf:%s ret:%d\n",
                           inet_ntoa(sender_node->other_addr.sin_addr),
                           ntohs(sender_node->other_addr.sin_port), buffer.buf, ret);

                    // 查找目标客户端
                    struct client_node *target_node = find_client_by_ip_port(inet_ntoa(buffer.other_addr.sin_addr), ntohs(buffer.other_addr.sin_port));
                    if (target_node != NULL)
                    {
                        char msg[2048];
                        snprintf(msg, sizeof(msg), "%s: %s", sender_node->name, buffer.buf);

                        ret = send(target_node->socket, msg, strlen(msg), 0);
                        printf("转发消息到客户端[ip:%s port:%d] buf:%s ret:%d\n",
                               inet_ntoa(target_node->other_addr.sin_addr),
                               ntohs(target_node->other_addr.sin_port), msg, ret);
                        if (ret <= 0)
                        {
                            printf("发送失败，可能客户端已断开连接\n");
                        }
                    }
                    else
                    {
                        printf("未找到目标客户端: ip=%s port=%d\n", inet_ntoa(buffer.other_addr.sin_addr), ntohs(buffer.other_addr.sin_port));
                        // 向发送者返回错误消息
                        char error_msg[100];
                        snprintf(error_msg, sizeof(error_msg), "错误: 未找到目标客户端 %s:%d", inet_ntoa(buffer.other_addr.sin_addr), ntohs(buffer.other_addr.sin_port));

                        send(socket_client, error_msg, strlen(error_msg), 0);
                    }
                }
                else
                {
                    printf("未找到发送者客户端: socket=%d\n", socket_client);
                }
            }
            else if (buffer.flag == 4)
            { // 获取好友在线列表
                struct client_node *node = find_client_by_socket(socket_client);
                if (node != NULL)
                {
                    char list[1024];
                    get_friend_online_list(node->name, list);
                    send(socket_client, list, strlen(list), 0);
                }
            }
            else if (buffer.flag == 6) // 处理客户端更新目标消息
            {
                // 查找目标客户端
                struct client_node *target_node = find_client_by_ip_port(inet_ntoa(buffer.other_addr.sin_addr), ntohs(buffer.other_addr.sin_port));
                if (target_node != NULL)
                {
                    send(socket_client, "Target Found", strlen("Target Found"), 0);
                }
                else
                {
                    send(socket_client, "Target Not Found", strlen("Target Not Found"), 0);
                }
            }
        }
    }
}

int main(int argc, char **argv)
{
    int ret;
    int socket_fd;
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        perror("socket fail");
        return -1;
    }

    init_client_list();
    bind_friends("client1", "client2");

    // 添加固定的用户信息
    strcpy(users[user_count].name, "1234");
    strcpy(users[user_count].passward, "1234");
    user_count++;

    strcpy(users[user_count].name, "6789");
    strcpy(users[user_count].passward, "6789");
    user_count++;

    // 添加 client2 的用户信息
    strcpy(users[user_count].name, "client2");
    strcpy(users[user_count].passward, "password");
    user_count++;

    int optval = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    ret = bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret < 0)
    {
        perror("bind fail");
        return -1;
    }
    printf("绑定成功 本机IP:%s 本机端口:%d\n", SERVER_IP, SERVER_PORT);

    ret = listen(socket_fd, 20);
    if (ret < 0)
    {
        perror("listen fail");
        return -1;
    }

    while (1)
    {
        int socket_client;
        struct sockaddr_in client_addr;
        socklen_t addrlen = sizeof(client_addr);
        socket_client = accept(socket_fd, (struct sockaddr *)&client_addr, &addrlen);
        if (socket_client < 0)
        {
            perror("accept fail");
            return -1;
        }
        char *ip = inet_ntoa(client_addr.sin_addr);
        int port = ntohs(client_addr.sin_port);
        printf("[新的客户端上线 ip:%s port:%d socket=%d]\n", ip, port, socket_client);

        // 保存客户端地址信息到临时列表
        add_temp_client(socket_client, client_addr);

        pthread_t tid;
        ret = pthread_create(&tid, NULL, recv_buf, &socket_client);
        if (ret < 0)
        {
            perror("pthread_create fail");
            close(socket_client);
            delete_temp_client(socket_client); // 创建线程失败时删除临时信息
            continue;
        }
    }

    close(socket_fd);
    return 0;
}